#define _GNU_SOURCE
#include "Buffer.h"
#include <stdio.h>
#include <stdlib.h>
#include <sys/uio.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <unistd.h>

//初始化
struct Buffer* bufferInit(int size)
{
    struct Buffer* buffer = (struct Buffer*)malloc(sizeof(struct Buffer));
    if(buffer != NULL)
    {
        buffer->data = (char*)malloc(sizeof(char) * size);
        memset(buffer->data, 0, sizeof(char) * size);
        buffer->capacity = size;
        buffer->writePos = buffer->readPos = 0;
    }
    return buffer;
}

//释放内存
void bufferDestroy(struct Buffer* buf)
{
    if(buf != NULL)
    {
        if(buf->data != NULL)
        {
            free(buf->data);
        }
        free(buf);
    }
}

//扩容
void bufferExtendRoom(struct Buffer* buffer, int size)
{
        //1.内存够用 - 不需要扩容
        if(bufferWriteAbleSize(buffer) >= size)
        {
            return;
        }
        //2.内存需要合并才够用 - 不需要扩容
        //剩余的可写内存 + 已读内存 >= size
        else if(buffer->readPos + bufferWriteAbleSize(buffer) >= size)
        {
            //得到未读的内存大小
            int readAble = bufferReadAbleSize(buffer);
            //拷贝内存（移动未读内存）
            memcpy(buffer->data, buffer->data + buffer->readPos, readAble);
            //更新位置
            buffer->readPos = 0;
            buffer->writePos = readAble;
        }
        //3.内存不够用 - 扩容
        else
        {
            void* tmp = realloc(buffer->data, buffer->capacity + size);
            if(tmp == NULL)
            {
                return;//失败
            }
            //初始化新开辟的空间
            memset(tmp + buffer->capacity, 0, size);
            //更新数据
            buffer->data = tmp;
            buffer->capacity += size;
        }

}

//得到剩余的可写的内存容量
int bufferWriteAbleSize(struct Buffer* buffer)
{
    return buffer->capacity - buffer->writePos;
}

//得到剩余的可读的内存容量
int bufferReadAbleSize(struct Buffer* buffer)
{
    return buffer->writePos - buffer->readPos;
}

//写内存 1.直接写 2.接收套接字数据
int bufferAppendData(struct Buffer* buffer, const char* data, int size)
{
    if(buffer == NULL || data == NULL || data <= 0)
    {
        return -1;
    }
    //判断是否需要扩容，如果需要扩容就扩容
    bufferExtendRoom(buffer, size);
    //数据拷贝
    memcpy(buffer->data + buffer->writePos, data, size);
    //更新数据
    buffer->writePos += size;
    return 0;
}

int bufferAppendString(struct Buffer* buffer, const char* data)
{
    int size = strlen(data);
    int ret = bufferAppendData(buffer, data, size);
    return 0;
}

int bufferSocketRead(struct Buffer* buffer, int fd)
{
    //read/recv/readv
    struct iovec vec[2];
    //初始化数组元素
    int writeAble = bufferWriteAbleSize(buffer);
    vec[0].iov_base = buffer->data + buffer->writePos;
    vec[0].iov_len = writeAble;
    char* tmpbuf = (char*)malloc(sizeof(char) * 40960);
    vec[1].iov_base = tmpbuf;
    vec[1].iov_len = 40960;
    int result = readv(fd, vec, 2);
    if(result == -1)
    {
        return -1;
    }
    else if(result <= writeAble)//全部写入到vec[0]
    {
        buffer->writePos += result;
    }
    else//vec[0]满了，两个vec都写了
    {
        buffer->writePos = buffer->capacity;//buf满了
        //将写入到tmpbuf中的数据写入到buffer中
        bufferAppendData(buffer, tmpbuf, result - writeAble);
    }
    free(tmpbuf);
    return result;
}

//根据\r\n取出一行，找到其在数据块中的位置，返回该位置
char* bufferFindCRLF(struct Buffer* buffer)
{
    //strstr --> 大字符串匹配子字符串(遇到\0结束)
    //memmem -- 大数据快中匹配子数据块(需要指定数据块大小)
    //void* memmem(const void* haystack, size_t haystacklen,
    //        const void* needle, size_t needlelen);
    char* ptr = memmem(buffer->data + buffer->readPos, bufferReadAbleSize(buffer), "\r\n", 2);
    return ptr;
}

//发送数据
int bufferSendData(struct Buffer* buffer, int socket)
{
    //判断有无数据
    int readable = bufferReadAbleSize(buffer);
    if(readable > 0)
    {
        int count = send(socket, buffer->data + buffer->readPos, readable, 0);
        if(count > 0)
        {
            buffer->readPos += count;
            usleep(1);//给接收端时间处理
        }
    }
    return 0;
}